package com.hanc.pay.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.gson.Gson;
import com.hanc.pay.config.WxPayConfig;
import com.hanc.pay.entity.OrderInfo;
import com.hanc.pay.entity.PaymentInfo;
import com.hanc.pay.entity.RefundInfo;
import com.hanc.pay.enums.OrderStatus;
import com.hanc.pay.enums.PayType;
import com.hanc.pay.enums.wxpay.WxRefundStatus;
import com.hanc.pay.service.OrderInfoService;
import com.hanc.pay.service.PaymentInfoService;
import com.hanc.pay.service.RefundInfoService;
import com.hanc.pay.service.WxPayService;
import com.hanc.pay.util.HttpUtils;
import com.hanc.pay.util.WechatPay2ValidatorForRequest;
import com.hanc.pay.vo.Result;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpResponse;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;

@RestController
@RequestMapping("/api/wx-pay")
@Api(tags = "调用微信下单API")
@Slf4j
public class WxPayController {
    @Resource
    private WxPayService wxPayService;

    @Resource
    private Verifier verifier;

    @Resource
    private WxPayConfig wxPayConfig;

    @Resource
    private OrderInfoService orderInfoService;

    @Resource
    private PaymentInfoService paymentInfoService;

    @Resource
    private RefundInfoService refundInfoService;

    @ApiOperation("调用统一SDK下单")
    @PostMapping("/nativePay/{productID}")
    public Result nativePay(@PathVariable Long productID) throws Exception {

        log.info("发起支付请求");
        Map<String,Object> maps = wxPayService.nativePay(productID);
        return Result.resultSuccess().setData(maps);

    }

    /**
     * 下单回调接口
     * @param request
     * @param response
     * @return
     */
    @PostMapping("/native/notify")
    public String nativePayNotify(HttpServletRequest request, HttpServletResponse response){
        log.info("进入支付回调通知");
        Gson gson = new Gson();

        //应答对象
        Map<String, String> stringHashMap = null;
        try {
            stringHashMap = new HashMap<>();
            //从请求头中获取data对象
            String readData = HttpUtils.readData(request);
            Map<String,Object> bodyMap = gson.fromJson(readData, HashMap.class);
            //请求id
            String id = (String) bodyMap.get("id");
            log.info("通知id ==>{}",id);
            log.info("回调完整参数 ==>{}",bodyMap);

            //验签
            WechatPay2ValidatorForRequest wechatPay2ValidatorForRequest = new WechatPay2ValidatorForRequest(verifier,id,readData);
            if (!wechatPay2ValidatorForRequest.validate(request)){
                log.info("通知验签失败");
                response.setStatus(500);
                stringHashMap.put("code","FAIL");
                stringHashMap.put("message","失败");
            }
            log.info("通知验签成功");

            //解密回调报文
            Map<String,String> resource=(Map<String,String>)bodyMap.get("resource");
            //数据密文
            String ciphertext=resource.get("ciphertext");
            //随机串
            String associatedData=resource.get("associated_data");
            //附加数据
            String nonce=resource.get("nonce");
            //获取明文
            String plainText=new AesUtil(wxPayConfig.getApiV3Key().getBytes(StandardCharsets.UTF_8)).decryptToString(associatedData.getBytes(StandardCharsets.UTF_8)
                    ,nonce.getBytes(StandardCharsets.UTF_8)
                    ,ciphertext);
            log.info("明文=====>{}",plainText);
            //将明文转换成map，从map里面获取订单号
            Map<String,Object> hashMap = gson.fromJson(plainText, HashMap.class);
            String tradeNo = (String) hashMap.get("out_trade_no");
            //订单处理
            //查询订单
            QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("order_no",tradeNo);
            OrderInfo info = orderInfoService.getOne(queryWrapper);
            if (info == null){
                log.info("查询订单异常");
            }
            synchronized (this){
                if (info.getOrderStatus().equals(OrderStatus.NOTPAY.getType())){
                    info.setOrderStatus(OrderStatus.SUCCESS.getType());
                    orderInfoService.updateById(info);

                    //获取订单金额
                    Map<String,Object> amount = (Map) hashMap.get("amount");
                    //用户支付金额，整型，单位为分。（指使用优惠券的情况下，这里等于总金额-优惠券金额）
                    Integer payerTotal = ((Double)amount.get("payer_total")).intValue();

                    PaymentInfo paymentInfo = new PaymentInfo(
                            info.getOrderNo(),
                            (String) hashMap.get("transaction_id "),//微信支付订单号
                            PayType.WXPAY.getType(),//支付类型
                            (String) hashMap.get("trade_type"),//交易类型
                            (String) hashMap.get("trade_state "),//交易状态
                            payerTotal,//订单金额
                            plainText
                    );
                    paymentInfo.setCreateTime(new Date());
                    paymentInfo.setUpdateTime(new Date());
                    paymentInfoService.save(paymentInfo);
                    log.info("订单{}的支付记录添加成功,支付记录id为{}.",info.getOrderNo(),paymentInfo.getId());
                }else {
                    log.debug("订单{}状态为{},回调处理退出.",info.getOrderNo(),info.getOrderStatus());
                }
            }
            response.setStatus(200);
            stringHashMap.put("code","SUCCESS");
            stringHashMap.put("message","成功");
        } catch (Exception e) {
            e.printStackTrace();

            response.setStatus(500);
            stringHashMap.put("code","FAIL");
            stringHashMap.put("message","失败");
        }
        return gson.toJson(stringHashMap);
    }

    /**
     * 取消订单
     * @param orderNo
     * @return
     * @throws Exception
     */
    @PostMapping("/closeNativePay/{orderNo}")
    public Result closeNativePay(@PathVariable String orderNo) throws Exception {
        log.info("取消订单");
        wxPayService.closeNativePay(orderNo);
        return Result.resultSuccess().setMessage("订单已取消");
    }

    /**
     * 查询订单
     * @param orderNo
     * @return
     * @throws Exception
     */
    @PostMapping("/queryOrder/{orderNo}")
    public Result queryOrder(@PathVariable String orderNo) throws Exception {
        log.info("查询订单");
        String params = wxPayService.queryOrder(orderNo);
        return Result.resultSuccess().setMessage("查询订单成功").data("result",params);
    }

    /**
     * 创建退款订单
     * @param orderNo
     * @return
     * @throws Exception
     */
    @PostMapping("/refunds/{orderNo}/{reason}")
    public Result refunds(@PathVariable String orderNo,@PathVariable String reason) throws Exception {
        log.info("创建退款订单");
        wxPayService.refunds(orderNo,reason);
        return Result.resultSuccess().setMessage("订单退款成功");
    }


    /**
     * 退款回调接口
     * @param request
     * @param response
     * @return
     */
    @PostMapping("/refunds/notify")
    public String refundsNotify(HttpServletRequest request, HttpServletResponse response){

        HashMap<String, Object> stringHashMap = new HashMap<>();
        try {
            String readData = HttpUtils.readData(request);
            log.info("回调参数====>{}",readData);
            HashMap bodyMap = new Gson().fromJson(readData, HashMap.class);
            //请求id
            String id = (String) bodyMap.get("id");
            log.info("通知id ==>{}",id);
            log.info("回调完整参数 ==>{}",bodyMap);

            //验签
            WechatPay2ValidatorForRequest wechatPay2ValidatorForRequest = new WechatPay2ValidatorForRequest(verifier,id,readData);
            if (!wechatPay2ValidatorForRequest.validate(request)){
                log.info("通知验签失败");
                response.setStatus(500);
                stringHashMap.put("code","FAIL");
                stringHashMap.put("message","失败");
            }
            log.info("通知验签成功");

            //解密回调报文
            Map<String,String> resource=(Map<String,String>)bodyMap.get("resource");
            //数据密文
            String ciphertext=resource.get("ciphertext");
            //随机串
            String associatedData=resource.get("associated_data");
            //附加数据
            String nonce=resource.get("nonce");
            //获取明文
            String plainText=new AesUtil(wxPayConfig.getApiV3Key().getBytes(StandardCharsets.UTF_8)).decryptToString(associatedData.getBytes(StandardCharsets.UTF_8)
                    ,nonce.getBytes(StandardCharsets.UTF_8)
                    ,ciphertext);
            log.info("获取明文====>{}",plainText);

            Map<String,Object> hashMap = new Gson().fromJson(plainText, HashMap.class);

            //查询退单表
            QueryWrapper<RefundInfo> queryWrapper=new QueryWrapper<>();
            queryWrapper.eq("refund_no",hashMap.get("out_refund_no"));
            RefundInfo refundInfo=refundInfoService.getOne(queryWrapper);

            synchronized(this){
                if(OrderStatus.REFUND_SUCCESS.getType().equals(refundInfo.getRefundStatus())){
                    //将退款状态设置为退款成功
                    refundInfo.setRefundStatus(WxRefundStatus.SUCCESS.getType());
                    //存放全部数据(json)以备不时之需
                    refundInfo.setContentNotify(plainText);
                    //更新退款
                    refundInfoService.updateById(refundInfo);
                    //更新订单的状态
                    String orderNo=refundInfo.getOrderNo();
                    QueryWrapper<OrderInfo> orderInfoQueryWrapper=new QueryWrapper<>();
                    orderInfoQueryWrapper.eq("order_no",orderNo);
                    OrderInfo orderInfoToUpdate=new OrderInfo();
                    orderInfoToUpdate.setOrderStatus(OrderStatus.REFUND_SUCCESS.getType());
                    orderInfoService.update(orderInfoToUpdate,orderInfoQueryWrapper);
                    log.debug("退款成功,退款单为{},对应的订单为{}.",refundInfo.getRefundNo(),refundInfo.getOrderNo());
                }
                else{
                    log.debug("退款单{}状态为{},回调处理退出.",refundInfo.getRefundNo(),refundInfo.getRefundStatus());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();

        }
        return new Gson().toJson(stringHashMap);
    }



}
